package com.aegis.common.web.xss;

import org.jsoup.safety.Safelist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * XSS攻击防御方式，通过过滤器按需过滤
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1) // Run early, but after basic Spring filters
public class XssResponseSanitizationFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(XssResponseSanitizationFilter.class);

    private final XssResponseFilterProperties properties;
    private final Safelist safelist; // Inject the custom Safelist
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    public XssResponseSanitizationFilter(XssResponseFilterProperties properties, Safelist customSafelist) {
        this.properties = properties;
        this.safelist = customSafelist;
        log.info("XssResponseSanitizationFilter initialized. Enabled: {}", properties.isEnabled());
        if (properties.isEnabled()) {
            log.info("Include paths: {}", properties.getIncludePaths());
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        if (!properties.isEnabled() || !isPathMatch(request.getRequestURI())) {
            filterChain.doFilter(request, response);
            return;
        }
        log.info("XSS过滤开启: {}", request.getRequestURI());
        XssHttpServletRequestWrapper responseWrapper = new XssHttpServletRequestWrapper(request, safelist);
        filterChain.doFilter(responseWrapper, response); // Continue chain with wrapped response
    }

    private boolean isPathMatch(String requestUri) {
        return properties.getIncludePaths().isEmpty() ||
                properties.getIncludePaths().stream().anyMatch(pattern -> pathMatcher.match(pattern, requestUri));
    }
}